﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using Collections;
using Collections.TreeCollections;
using FeatureModel.Collections.TreeArgs;
using EventLogAssembly;

namespace TreeGraphicalControl
{
    public abstract class TreeViewControl : TreeView
    {
        public Tree TreeInstance { get { if (_versionController == null) return null; return this._versionController.CurrentTree; } }

        #region Fields
        protected string _Tree_ID = "Tree";
        protected TreeVersionController _versionController;
        protected TreeViewItemGenerator _menuGenerator;
        #endregion

        public TreeViewControl()
        {
            _versionController = null;
            _menuGenerator = null;
        }

        /// <summary>
        /// Bind Tree View Item Generator
        /// </summary>
        /// <param name="generator"></param>
        public virtual void BindGenerator(TreeViewItemGenerator generator)
        {
            _menuGenerator = generator;
        }

        /// <summary>
        /// Bind tree object
        /// </summary>
        /// <param name="tree"></param>
        /// <returns></returns>
        public virtual bool Bind(Tree tree)
        {
            if (this.validControl() == false)
            {
                return false;
            }

            _versionController = new TreeVersionController(tree);
            TreeRefreshEventHandler rd = this.Refresh;
            tree.TreeModifyCompleted.AddHandler( (sender, args) =>
                {
                    this.Dispatcher.BeginInvoke(rd, sender, args);
                });

            Refresh(this, null);
            return true;
        }
        /// <summary>
        /// Refresh whole feature model
        /// </summary>
        public virtual void Refresh(object sender, TreeEventArgs args)
        {
            if (this.validControl() == false)
            {
                return;
            }

            TreeViewItemControl[] orgItems = null;
            // get original tree object
            Tree curTree = _versionController.CurrentTree;
            Tree orgTree = _versionController.PeekUndo();

            if (orgTree != null)
            {
                // reverse former tree view status
                orgItems = new TreeViewItemControl[orgTree.Count];
                fetchAllTreeViewItems(orgItems, this);
            }
            // clear
            this.Items.Clear();

            // generate root
            try
            {
                // create root item
                TreeViewItemControl rootItem = _menuGenerator
                    .GenerateTreeItemRoot(curTree.Root, orgItems);

                this.Items.Add(rootItem);

                // generate tree view
                generateTree(curTree.Root, rootItem, orgItems);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
        /// <summary>
        /// Valid Tree View Item Control
        /// </summary>
        protected virtual bool validControl()
        {
            return _menuGenerator != null;
        }
        /// Generate Tree
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="item"></param>
        protected virtual void generateTree(TreeObject obj, TreeViewItemControl item
            , TreeViewItemControl[] orgItems)
        {
            INonLeaf nonLeaf = obj as INonLeaf;
            if (nonLeaf == null)
            {
                return;
            }
            foreach (INonRoot nonRoot in nonLeaf.Children)
            {
                TreeObject child = nonRoot as TreeObject;
                if (child == null)
                {
                    continue;
                }

                TreeViewItemControl newItem = _menuGenerator.GenerateTreeItem(child, orgItems);
                item.Items.Add(newItem);
                generateTree(child, newItem, orgItems);
            }
        }
        /// <summary>
        /// push all orgTreeView
        /// </summary>
        /// <param name="items"></param>
        /// <param name="orgTreeView"></param>
        protected void fetchAllTreeViewItems(TreeViewItemControl[] items, TreeViewControl orgTreeView)
        {
            // cursor for insert place, cur for extend place
            int cursor = 0, cur = 0;
            try
            {
                items[cursor++] = (TreeViewItemControl)orgTreeView.Items[0];
                for (; cur < cursor && cursor < items.Length; cur++)
                {
                    foreach (TreeViewItemControl item in items[cur].Items)
                    {
                        items[cursor++] = item;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

    }
}
